import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import * as cp from 'child_process';
import { env } from 'process';
import { getParentCompileDir, getEditor, interceptErr } from './utils';


// 定义一个常量来匹配 .img 文件
const IMG_FILE_PATTERN = /boot\.img$/i;
let ramDir: string = "ramdisk";
let outDir: string = "out";
let bootDir: string = "boot"
const initrdImg = `initrd.img`;
const initrdGz = 'initrd.img.gz';
const abootimgPath = path.join(__dirname, 'abootimg'); // 假设 abootimg 工具位于扩展的根目录
const logoImgToolPath = path.join(__dirname, 'aml-imgpack.py');
const BootImg: {ramdisk: string, cfg: string, kernel: string, stage2: string} = {
    ramdisk: `${bootDir}/tmp/initrd.img`,
    kernel: `${bootDir}/tmp/zImage`,
    stage2: `${bootDir}/tmp/stage2.img`,
    cfg: `${bootDir}/tmp/bootimg.cfg`
}


// 定义一个命令来解压 .img 文件
function unpackBootImg(uri: vscode.Uri): void {
    const filePath = uri.fsPath
    const fileName = path.basename(filePath);
	const bootimgDir = path.dirname(filePath)

    const workingDir = `${bootimgDir}/${bootDir}`
    const ramdiskDir = `${workingDir}/${ramDir}`
    const outputDir = `${workingDir}/${outDir}`
    const tmpDir = `${workingDir}/tmp`
    const preareCmd = `chmod 755 ${abootimgPath};
        rm -rf ${workingDir};
        mkdir -p ${workingDir};
        mkdir -p ${tmpDir};
        mkdir -p ${ramdiskDir};
        mkdir -p ${outputDir}`
    const extractCmd = `"${abootimgPath}" -x "./${fileName}" ${BootImg.cfg} ${BootImg.kernel} ${BootImg.ramdisk} ${BootImg.stage2}`;
    const clearCmd = `rm ${initrdImg};rm -rf "${tmpDir}"`

    const cmd = `
        ${preareCmd};
        ${extractCmd};
        mv ${BootImg.ramdisk} ${ramdiskDir}/${initrdGz};
        cp "${filePath}" "${outputDir}";
        cd "${ramdiskDir}";
        gzip -d ${initrdGz};
        cpio -i < ${initrdImg};
        ${clearCmd}`
    try {
        cp.exec(cmd, {cwd: bootimgDir}, (error, stdout) => {
            interceptErr(error);
            // vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.parse(workingDir));
            console.log('The .img file has been successfully decompressed.');
        });
    } catch (error: any) {
        console.error(`Error executing command: ${error.stack || error}`);  // Log the stack trace for detailed debugging
        vscode.window.showErrorMessage(`Failed to decompress the .img file: ${error}`);
    }
}


// 定义一个命令打包 .img 文件
function packBootImg(uri: vscode.Uri): void {
    const cwd = uri.fsPath;
    // const cwd = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.path : "";

    const outputDir = `${cwd}/${outDir}`
    const srcDir = `${cwd}/${ramDir}`

    console.log(`cwd: ${cwd}, srcDir: ${srcDir}`);

    const buildCmd = `find . | cpio --create --format=newc > ${outputDir}/${initrdImg};gzip ${outputDir}/${initrdImg}`;
    let saveCmd = `${outputDir}/boot.img;${abootimgPath} -u ${outputDir}/boot.img -r ${outputDir}/${initrdGz}`;
    const clearCmd = `rm -rf ${outputDir}/${initrdImg};rm -rf ${outputDir}/${initrdGz}`;
    if (!fs.existsSync(abootimgPath)) {
        vscode.window.showErrorMessage('The abootimg tool is missing.');
        return;
    }

    try {
        cp.exec(buildCmd, {cwd: srcDir}, (error, stdout) => {
            console.log("cmd:" + buildCmd);
            
            interceptErr(error);
            cp.exec(saveCmd, (error, stdout) => {
                if (error) {
                    console.error(`stderr: ${error.message}`);
                    const sizeRegex = /updated is too big for the Boot Image \((\d+) vs \d+ bytes\)/;
                    const match = error.message.match(sizeRegex);
                    
                    if (match && match[1]) {
                        const updatedSize = parseInt(match[1], 10);
                        saveCmd += ` -c bootsize==${updatedSize}`;
                        cp.exec(saveCmd, (error) => interceptErr(error))
                    } else {
                        console.log("No size found in the error message.");
                    }
                    return;
                }

                cp.exec(clearCmd);
                vscode.window.showInformationMessage('The .img file has been successfully packaged.');
            });
        });

    } catch (error: any) {
        console.error(`Error executing command: ${error.stack || error}`);  // Log the stack trace for detailed debugging
        vscode.window.showErrorMessage(`Failed to decompress the .img file: ${error}`);
    }
}


function unpackLogoImg(uri: vscode.Uri): void {
    const filePath = uri.fsPath;
    // const editor = getEditor();
    // const filePath = editor.document.fileName;
	const logoImgDir = path.dirname(filePath);
    console.log(`filePath: ${filePath}, , logoImgToolPath: ${logoImgToolPath}, logoImgDir: ${logoImgDir}`);
    const outDir = `${logoImgDir}/logo`;
    const cmd = `chmod 755 ${logoImgToolPath};
        rm -rf ${outDir};mkdir -p ${outDir} && cd ${outDir};${logoImgToolPath} --unpack ${filePath};open ${outDir}`;
    console.log(`cmd: ${cmd}`);
    try {
        cp.exec(cmd, {cwd: logoImgDir}, (error) => interceptErr(error));
    } catch (error: any) {
        console.error(`Error executing command: ${error.stack || error}`);
        vscode.window.showErrorMessage(`Failed to unpack the logo.img file: ${error}`);
    }

}

function packLogoImg(uri: vscode.Uri): void {

    const logoDir = uri.fsPath
    const cmd = `${logoImgToolPath} --pack logo.img *.bmp`
    console.log(`cwd: ${logoDir}\n\ncmd: ${cmd}`);
    try {
        cp.exec(cmd, {cwd: logoDir}, (error) => {
            interceptErr(error);
            vscode.window.showInformationMessage('The logo.img file has been successfully packaged.');

        });
    } catch (error: any) {
        console.error(`Error executing command: ${error.stack || error}`);
        vscode.window.showErrorMessage(`Failed to pack the logo.img file: ${error}`);
    }
}

/**
 * 编译模块
 *
 * @param filePath 文件路径
 * @returns 编译是否成功
 */
function compileModule(): void {
    const editor = getEditor();
    const filePath = editor.document.fileName;

    const compileRoot = env.COMPILE_ROOT_DIR;
    if (compileRoot == undefined) {
        vscode.window.showErrorMessage('The enviroment variable COMPILE_ROOT_DIR is not set.');
        return;
    }

    const compileDir = getParentCompileDir(filePath);
    console.log(`compileDir: ${compileDir}`);
    if (compileDir == null) {
        vscode.window.showErrorMessage('The active file is not in a module.');
        return;
    }
    try {
        // 创建一个新的终端实例
        let terminal = vscode.window.terminals.find(t => t.name === 'Compile Terminal');
        console.log(`terminal: ${terminal}`);
        if (terminal == undefined) {
            terminal = vscode.window.createTerminal({
                name: 'Compile Terminal', // 终端的名称
                cwd: compileRoot, // 设置终端的工作目录
                hideFromUser: false // 设置为 true 则终端不会自动显示给用户，需要通过命令面板手动显示
            });
        }
        const cmd = `cd ${compileRoot};./compile.sh -m ${path.relative(compileRoot, compileDir)}`;
        console.log(`copmile cmd: ${cmd}`);
        terminal.show();
        terminal.sendText(cmd);

        return;
    } catch (error: any) {
        vscode.window.showErrorMessage(`An error occurred: ${error.message}`);
        return;
    }
}

function downloadFile(uri: vscode.Uri): void {
    const filePath = uri.fsPath;
    const downloadDir = env.REMOTE_DOWNLOAD_DIR;
    if (downloadDir == undefined) {
        vscode.window.showErrorMessage('The enviroment variable REMOTE_DOWNLOAD_DIR is not set.');
        return;
    }
    try {
        cp.exec(`scp -r ${filePath} ${downloadDir}`, (error) => interceptErr(error));
    } catch (error: any) {
        console.error(`Error executing command: ${error.stack || error}`);
        vscode.window.showErrorMessage(`Failed to download the file: ${error}`);
    }
    console.log('Download success!');

}

// 定义一个事件监听器来处理文件打开事件
export function activate(context: vscode.ExtensionContext): void {
    console.log("activate");

    updateCwdContext();

    const unpackBootImgDisposable = vscode.commands.registerCommand('abootimg.openBootImg', unpackBootImg);
    const packBootImgDisposable = vscode.commands.registerCommand('abootimg.saveBootImg', packBootImg);
    const unpackLogoImgDisposable = vscode.commands.registerCommand('abootimg.openLogoImg', unpackLogoImg);
    const packLogoImgDisposable = vscode.commands.registerCommand('abootimg.saveLogoImg', packLogoImg);
    const downloadFileDisposable = vscode.commands.registerCommand('abootimg.downloadFile', downloadFile);
    const compileModuleDisposable = vscode.commands.registerCommand('abootimg.compileModule', compileModule);

    context.subscriptions.push(unpackBootImgDisposable);
    context.subscriptions.push(packBootImgDisposable);
    context.subscriptions.push(unpackLogoImgDisposable);
    context.subscriptions.push(packLogoImgDisposable);
    context.subscriptions.push(downloadFileDisposable);
    context.subscriptions.push(compileModuleDisposable);

}

function updateCwdContext() {
    const cwd = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0] : undefined;

    const isInitrd = cwd?.name == 'initrd'; // Check if CWD is 'initrd'
    console.log(`cwd: ${cwd}, isInitrd: ${isInitrd}`);
    vscode.commands.executeCommand('setContext', 'isInitrd', isInitrd); // Set context key
  }
  
  module.exports = { activate };